/******************************************************************************
 *                                                                          
 * Copyright (c) 2008 Nuvoton Technology. All rights reserved.             
 *                                                                
 * 
 * FILENAME
 *     NUC900_UDA1345TS.c
 *
 * VERSION
 *     0.1 
 *
 * DESCRIPTION
 *
 *
 *
 *
 * DATA STRUCTURES
 *     None
 *
 * FUNCTIONS
 *
 *
 *     
 * HISTORY
 *     2007.09.29		Created by Shih-Jen Lu
 *
 *
 * REMARK
 *     None
 *
 *
 **************************************************************************/
#ifdef ECOS
#include "stdio.h"
#include "stdlib.h"
#include "kapi.h"
#include "diag.h"
#else
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wblib.h"
#endif

#include "wbio.h"
//
#include "NUC900_Audio_Regs.h"
#include "NUC900_Audio.h"

#include "IIS.h"
#include "UDA1345TS.h"

#ifdef HAVE_I2S_UDA1345

#define REG_GPIO_DATAOUT REG_GPIOC_DATAOUT


static UINT8 _cCodecStatus;



VOID L3_Set_Data(UINT8);
VOID L3_Set_Status(UINT8);
static void Delay(int nCnt)
{
	 int volatile loop;
	for (loop=0; loop<nCnt*10; loop++);
}
static BOOL uda1345tsSetSampleRate(UINT16 SampleRate)
{
    UINT8 nStatus=0;
    BOOL bRetVal=TRUE;
	switch (SampleRate)
	{
		case AU_SAMPLE_RATE_8000:							//8KHz
			nStatus = EX_384FS;
			break;
		case AU_SAMPLE_RATE_12000:							//12KHz
			nStatus = EX_256FS;
			break;
		case AU_SAMPLE_RATE_11025:					//11.025KHz
			nStatus = EX_384FS;
			break;
		case AU_SAMPLE_RATE_16000:						//16KHz
			nStatus = EX_384FS;
			break;
		case AU_SAMPLE_RATE_22050:					//22.05KHz
			nStatus = EX_256FS;
			break;
		case AU_SAMPLE_RATE_24000:						//24KHz
			nStatus = EX_256FS;
			break;
		case AU_SAMPLE_RATE_32000:						//32KHz
			nStatus = EX_384FS;
			break;
		case AU_SAMPLE_RATE_44100:					//44.1KHz
			nStatus = EX_384FS;
			break;
		case AU_SAMPLE_RATE_48000:						//48KHz
			nStatus = EX_256FS;
			break;
		default:
		    bRetVal = FALSE;
		    break;
	}
	
	switch(g_I2SAudioFormat){
		case I2S_FORMAT: nStatus |= EX_IIS;
				break;
		case MSB_FORMAT: nStatus |= EX_MSB;
				break;
		default:break;
	}
	
	L3_Set_Status(nStatus);
	
	return TRUE;
}


BOOL uda1345tsPowerOn(WAPI_INOUT apidir ,PWAVEFORMATEX pFormat)
{
    UINT8 L3Data;
    if(apidir==WAPI_OUT)
    {
        if (uda1345tsSetSampleRate(pFormat->nSamplesPerSec)==FALSE)
        {
            _debug_msg("Error - sample rate %d not support!!\n",pFormat->nSamplesPerSec);
		    return FALSE;
        }
        
        L3Data = 0x80;						
	    L3_Set_Data(L3Data);//no de-emphasis,disable DAC mute
        
        _cCodecStatus = _cCodecStatus | EX_DAC_On;
	    L3_Set_Data(_cCodecStatus);//power up DAC
	    
	    uda1345tsSetPlayVolume(v_nVolume);//set default volume
    }
    else
    {
        uda1345tsSetSampleRate(pFormat->nSamplesPerSec);
        
        _cCodecStatus = _cCodecStatus | EX_ADC_On;
	    L3_Set_Data(_cCodecStatus);//power up ADC
	    
    }
     
    return TRUE;
}



/*----------- for UDA1345TS functions group ----------*/

/* L3 Address mode */
void L3_Address_Mode(volatile UINT8 L3Data){
	int i;
	
	for (i=0;i<8;i++)
	{
		
		writew(REG_GPIO_DATAOUT, readw(REG_GPIO_DATAOUT) &~L3MODE_GPIO_NUM | L3CLOCK_GPIO_NUM);
		Delay(10);
		if ((1 << i) & L3Data)
		{
			//_debug_msg("1\n");	
			writew(REG_GPIO_DATAOUT, readw(REG_GPIO_DATAOUT) &~L3MODE_GPIO_NUM &~L3CLOCK_GPIO_NUM | L3DATA_GPIO_NUM);
		}	
		else 
		{	//_debug_msg("0\n");	
			writew(REG_GPIO_DATAOUT, readw(REG_GPIO_DATAOUT) &~L3MODE_GPIO_NUM &~L3CLOCK_GPIO_NUM &~L3DATA_GPIO_NUM);
		}	
		Delay(10);
	}
	writew(REG_GPIO_DATAOUT, readw(REG_GPIO_DATAOUT) &~L3MODE_GPIO_NUM | L3CLOCK_GPIO_NUM);
}

/* L3 data transfer mode */
void L3_Data_Transfer_Mode(UINT8 L3Data){
	int i;
	
	for (i=0;i<8;i++)
	{
		writew(REG_GPIO_DATAOUT, readw(REG_GPIO_DATAOUT) | L3MODE_GPIO_NUM | L3CLOCK_GPIO_NUM );
		Delay(10);
		if ((1 << i) & L3Data)
		{
			//_debug_msg("1\n");
			writew(REG_GPIO_DATAOUT, readw(REG_GPIO_DATAOUT) & ~L3CLOCK_GPIO_NUM | L3MODE_GPIO_NUM | L3DATA_GPIO_NUM);
		}	
		else 
		{
			//_debug_msg("0\n");
			writew(REG_GPIO_DATAOUT, readw(REG_GPIO_DATAOUT) & ~L3CLOCK_GPIO_NUM & ~L3DATA_GPIO_NUM | L3MODE_GPIO_NUM);
		}
		Delay(10);
	}
	writew(REG_GPIO_DATAOUT, readw(REG_GPIO_DATAOUT) | L3MODE_GPIO_NUM | L3CLOCK_GPIO_NUM);
}

void L3_Set_Data(volatile UINT8 data){

	volatile UINT8 L3Data = 0;
	
	
	/*----- Address Mode -----*/
	L3Data = L3Data | EX_1345ADDR | EX_DATA; //set the DATA(volumn,de-emphasis, mute, and power control)
	L3_Address_Mode(L3Data);	
		
	/*----- Data Transfer Mode -----*/
	//L3Data = 0x0;						//set the maximum volumn
	L3_Data_Transfer_Mode(data);
	
	//writew(REG_GPIO_DATAOUT,readw(REG_GPIO_DATAOUT) & ~L3MODE_GPIO_NUM | L3CLOCK_GPIO_NUM );//transfer gap
	
	//L3Data = data;						//power control turn on the DAC or ADC
	//L3_Data_Transfer_Mode(L3Data);
	
	//writew(REG_GPIO_DATAOUT,readw(REG_GPIO_DATAOUT) & ~L3MODE_GPIO_NUM | L3CLOCK_GPIO_NUM );//transfer gap
	
	//L3Data = 0x80;						
	//L3_Data_Transfer_Mode(L3Data);
	
	
}

/*----- Set L3 nStatus -----*/
VOID L3_Set_Status(UINT8 nStatus){
	
	volatile UINT8 L3Data = 0;
	/*----- Address Mode -----*/
	L3Data = L3Data | EX_1345ADDR | EX_STATUS;	//set the STATUS(system clock frequency, data input format and DC filter)
	L3_Address_Mode(L3Data);	
	
	/*----- Data Transfer Mode -----*/
	L3_Data_Transfer_Mode(nStatus);
	
}




/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*      uda1345tsSetPlayVolume                                                   */
/*                                                                       */
/* DESCRIPTION                                                           */
/*      Set AC97 left and right channel play volume.                     */
/*                                                                       */
/* INPUTS                                                                */
/*      uVolume    play volume of left & right channel                   */
/*                 16 bits of right (0xRRRRLLLL)                         */
/*                  0:  mute                                             */
/*             0xffff: maxmum volume                                     */
/*                                                                       */
/*                                                                       */
/* OUTPUTS                                                               */
/*      None                                                             */
/*                                                                       */
/* RETURN                                                                */
/*      0           Success                                              */
/*		Otherwise	error												 */
/*                                                                       */
/*************************************************************************/
INT  uda1345tsSetPlayVolume(UINT32 uVolume)
{
    UINT8   data;
    UINT16 ucVolL;
    UINT16 ucVolR;
    UINT16 ucVolSet;
    
    ucVolR=(UINT16) (uVolume & 0x0000FFFF) >> 10; // six bits of volume
	ucVolL=(UINT16) ((uVolume & 0xFFFF0000)>>16) >> 10;  //six bits of volume
	
	if (ucVolR>ucVolL)
	{
	    ucVolSet = ucVolR;
	}
	else
	{
	    ucVolSet = ucVolL;
	}

	data = (UINT8)(ucVolSet & 0x003f);
	data = 0x3f - data; 
	
	L3_Set_Data(data);
	return 0;
}
BOOL
uda1345SetOutMute(BOOL mute)
{
    UINT8 data;
    if (mute)
        data = 0x80 | (1<<2);
    else
        data = 0x80;
    L3_Set_Data(data);
    
    return TRUE;
        
}

#endif	/* HAVE_I2S_UDA1345 */